<?php

namespace StrategyManager\Engine;

use Contract\Exceptions\LogicException;
use Contract\Exceptions\ValidationException;
use Psr\Container\ContainerInterface;

class StrategyEngine implements StrategyEngineInterface
{
    const NAME_INTERFACE = 'interface';
    const NAME_MAP = 'map';

    protected array $config;
    protected ContainerInterface $container;

    public function __construct(ContainerInterface $container)
    {
        $this->container = $container;
    }


    /**
     * @param array $config
     * @return void
     * @throws ValidationException
     */
    public function setConfig(array $config): void
    {
        $this->validateConfig($config);
        $this->config = $config;
    }

    /**
     * @param array $config
     * @return void
     * @throws ValidationException
     */
    protected function validateConfig(array $config): void
    {
        if (empty($config)) {
            throw new ValidationException('config 不能为空');
        }

        foreach ($config as $groupItem) {
            $groupInterface = $groupItem[static::NAME_INTERFACE];
            $groupMap = $groupItem[static::NAME_MAP];
            if (empty($groupInterface)) {
                throw new ValidationException('group 不能没有' . static::NAME_INTERFACE . '键值');
            }
            if (empty($groupMap)) {
                throw new ValidationException('group 不能没有' . static::NAME_MAP . '键值');
            }
            if (!is_array($groupMap)) {
                throw new ValidationException('group.' . static::NAME_MAP . ' 必须是数组');
            }
            foreach ($groupMap as $className) {
                if (!is_string($className)) {
                    throw new ValidationException('className 必须是字符串');
                }
            }
        }
    }

    /**
     * @param string $groupName
     * @param string $strategyName
     * @param array $parameters
     * @return mixed
     * @throws ValidationException|LogicException
     */
    public function getStrategyInstance(string $groupName, string $strategyName, array $parameters = [])
    {
        if (!isset($this->config[$groupName])) {
            throw new ValidationException("[groupName]$groupName 不存在");
        }
        $groupInterface = $this->config[$groupName][static::NAME_INTERFACE];
        $groupMap = $this->config[$groupName][static::NAME_MAP];
        if (!isset($groupMap[$strategyName])) {
            throw new ValidationException("[strategyName]$strategyName 不存在");
        }
        if (!empty($this->container) && method_exists($this->container, 'make')) {
            $strategyInstance = $this->container->make($groupMap[$strategyName], $parameters);
        } else {
            $parameters = array_values($parameters);
            $strategyInstance = new $groupMap[$strategyName](...$parameters);
        }
        if (!($strategyInstance instanceof $groupInterface)) {
            throw new LogicException("[strategyName]$strategyName 并没有继承 [interface]$groupInterface");
        }
        return $strategyInstance;
    }
}